<?php
/**
 * Zend Framework
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is bundled
 * with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://framework.zend.com/license/new-bsd
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@zend.com so we can send you a copy immediately.
 *
 * @category   Zend
 * @package    Zend_Form
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 */

/** Zend_Form_Decorator_Abstract */
require_once 'Zend/Form/Decorator/Abstract.php';

/**
 * Zend_Form_Decorator_ViewHelper
 *
 * Decorate an element by using a view helper to render it.
 *
 * Accepts the following options:
 * - separator: string with which to separate passed in content and generated content
 * - placement: whether to append or prepend the generated content to the passed in content
 * - helper:    the name of the view helper to use
 *
 * Assumes the view helper accepts three parameters, the name, value, and
 * optional attributes; these will be provided by the element.
 *
 * @category   Zend
 * @package    Zend_Form
 * @subpackage Decorator
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
 * @version    $Id: ViewHelper.php 23775 2011-03-01 17:25:24Z ralph $
 */
class Zend_Form_Decorator_ViewHelper extends Zend_Form_Decorator_Abstract {
	/**
	 * Element types that represent buttons
	 * @var array
	 */
	protected $_buttonTypes = array ('Zend_Form_Element_Button', 'Zend_Form_Element_Reset', 'Zend_Form_Element_Submit' );
	
	/**
	 * View helper to use when rendering
	 * @var string
	 */
	protected $_helper;
	
	/**
	 * Set view helper to use when rendering
	 *
	 * @param  string $helper
	 * @return Zend_Form_Decorator_Element_ViewHelper
	 */
	public function setHelper($helper) {
		$this->_helper = ( string ) $helper;
		return $this;
	}
	
	/**
	 * Retrieve view helper for rendering element
	 *
	 * @return string
	 */
	public function getHelper() {
		if (null === $this->_helper) {
			$options = $this->getOptions ();
			if (isset ( $options ['helper'] )) {
				$this->setHelper ( $options ['helper'] );
				$this->removeOption ( 'helper' );
			} else {
				$element = $this->getElement ();
				if (null !== $element) {
					if (null !== ($helper = $element->getAttrib ( 'helper' ))) {
						$this->setHelper ( $helper );
					} else {
						$type = $element->getType ();
						if ($pos = strrpos ( $type, '_' )) {
							$type = substr ( $type, $pos + 1 );
						}
						$this->setHelper ( 'form' . ucfirst ( $type ) );
					}
				}
			}
		}
		
		return $this->_helper;
	}
	
	/**
	 * Get name
	 *
	 * If element is a Zend_Form_Element, will attempt to namespace it if the
	 * element belongs to an array.
	 *
	 * @return string
	 */
	public function getName() {
		if (null === ($element = $this->getElement ())) {
			return '';
		}
		
		$name = $element->getName ();
		
		if (! $element instanceof Zend_Form_Element) {
			return $name;
		}
		
		if (null !== ($belongsTo = $element->getBelongsTo ())) {
			$name = $belongsTo . '[' . $name . ']';
		}
		
		if ($element->isArray ()) {
			$name .= '[]';
		}
		
		return $name;
	}
	
	/**
	 * Retrieve element attributes
	 *
	 * Set id to element name and/or array item.
	 *
	 * @return array
	 */
	public function getElementAttribs() {
		if (null === ($element = $this->getElement ())) {
			return null;
		}
		
		$attribs = $element->getAttribs ();
		if (isset ( $attribs ['helper'] )) {
			unset ( $attribs ['helper'] );
		}
		
		if (method_exists ( $element, 'getSeparator' )) {
			if (null !== ($listsep = $element->getSeparator ())) {
				$attribs ['listsep'] = $listsep;
			}
		}
		
		if (isset ( $attribs ['id'] )) {
			return $attribs;
		}
		
		$id = $element->getName ();
		
		if ($element instanceof Zend_Form_Element) {
			if (null !== ($belongsTo = $element->getBelongsTo ())) {
				$belongsTo = preg_replace ( '/\[([^\]]+)\]/', '-$1', $belongsTo );
				$id = $belongsTo . '-' . $id;
			}
		}
		
		$element->setAttrib ( 'id', $id );
		$attribs ['id'] = $id;
		
		return $attribs;
	}
	
	/**
	 * Get value
	 *
	 * If element type is one of the button types, returns the label.
	 *
	 * @param  Zend_Form_Element $element
	 * @return string|null
	 */
	public function getValue($element) {
		if (! $element instanceof Zend_Form_Element) {
			return null;
		}
		
		foreach ( $this->_buttonTypes as $type ) {
			if ($element instanceof $type) {
				if (stristr ( $type, 'button' )) {
					$element->content = $element->getLabel ();
					return null;
				}
				return $element->getLabel ();
			}
		}
		
		return $element->getValue ();
	}
	
	/**
	 * Render an element using a view helper
	 *
	 * Determine view helper from 'viewHelper' option, or, if none set, from
	 * the element type. Then call as
	 * helper($element->getName(), $element->getValue(), $element->getAttribs())
	 *
	 * @param  string $content
	 * @return string
	 * @throws Zend_Form_Decorator_Exception if element or view are not registered
	 */
	public function render($content) {
		$element = $this->getElement ();
		
		$view = $element->getView ();
		if (null === $view) {
			require_once 'Zend/Form/Decorator/Exception.php';
			throw new Zend_Form_Decorator_Exception ( 'ViewHelper decorator cannot render without a registered view object' );
		}
		
		if (method_exists ( $element, 'getMultiOptions' )) {
			$element->getMultiOptions ();
		}
		
		$helper = $this->getHelper ();
		$separator = $this->getSeparator ();
		$value = $this->getValue ( $element );
		$attribs = $this->getElementAttribs ();
		$name = $element->getFullyQualifiedName ();
		$id = $element->getId ();
		$attribs ['id'] = $id;
		
		$helperObject = $view->getHelper ( $helper );
		if (method_exists ( $helperObject, 'setTranslator' )) {
			$helperObject->setTranslator ( $element->getTranslator () );
		}
		
		$elementContent = $view->$helper ( $name, $value, $attribs, $element->options );
		switch ($this->getPlacement ()) {
			case self::APPEND :
				return $content . $separator . $elementContent;
			case self::PREPEND :
				return $elementContent . $separator . $content;
			default :
				return $elementContent;
		}
	}
}
